import {Group} from '../../objects/Group.js';

function WebXRController() {

  this._targetRay = null;
  this._grip = null;
  this._hand = null;

}

Object.assign(WebXRController.prototype, {

  constructor: WebXRController,

  getHandSpace: function () {

    if (this._hand === null) {

      this._hand = new Group();
      this._hand.matrixAutoUpdate = false;
      this._hand.visible = false;

      this._hand.joints = [];
      this._hand.inputState = {pinching: false};

      if (window.XRHand) {

        for (let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i++) {

          // The transform of this joint will be updated with the joint pose on each frame
          const joint = new Group();
          joint.matrixAutoUpdate = false;
          joint.visible = false;
          this._hand.joints.push(joint);
          // ??
          this._hand.add(joint);

        }

      }

    }

    return this._hand;

  },

  getTargetRaySpace: function () {

    if (this._targetRay === null) {

      this._targetRay = new Group();
      this._targetRay.matrixAutoUpdate = false;
      this._targetRay.visible = false;

    }

    return this._targetRay;

  },

  getGripSpace: function () {

    if (this._grip === null) {

      this._grip = new Group();
      this._grip.matrixAutoUpdate = false;
      this._grip.visible = false;

    }

    return this._grip;

  },

  dispatchEvent: function (event) {

    if (this._targetRay !== null) {

      this._targetRay.dispatchEvent(event);

    }

    if (this._grip !== null) {

      this._grip.dispatchEvent(event);

    }

    if (this._hand !== null) {

      this._hand.dispatchEvent(event);

    }

    return this;

  },

  disconnect: function (inputSource) {

    this.dispatchEvent({type: 'disconnected', data: inputSource});

    if (this._targetRay !== null) {

      this._targetRay.visible = false;

    }

    if (this._grip !== null) {

      this._grip.visible = false;

    }

    if (this._hand !== null) {

      this._hand.visible = false;

    }

    return this;

  },

  update: function (inputSource, frame, referenceSpace) {

    let inputPose = null;
    let gripPose = null;
    let handPose = null;

    const targetRay = this._targetRay;
    const grip = this._grip;
    const hand = this._hand;

    if (inputSource) {

      if (hand && inputSource.hand) {

        handPose = true;

        for (let i = 0; i <= window.XRHand.LITTLE_PHALANX_TIP; i++) {

          if (inputSource.hand[i]) {

            // Update the joints groups with the XRJoint poses
            const jointPose = frame.getJointPose(inputSource.hand[i], referenceSpace);
            const joint = hand.joints[i];

            if (jointPose !== null) {

              joint.matrix.fromArray(jointPose.transform.matrix);
              joint.matrix.decompose(joint.position, joint.rotation, joint.scale);
              joint.jointRadius = jointPose.radius;

            }

            joint.visible = jointPose !== null;

            // Custom events

            // Check pinch
            const indexTip = hand.joints[window.XRHand.INDEX_PHALANX_TIP];
            const thumbTip = hand.joints[window.XRHand.THUMB_PHALANX_TIP];
            const distance = indexTip.position.distanceTo(thumbTip.position);

            const distanceToPinch = 0.02;
            const threshold = 0.005;

            if (hand.inputState.pinching && distance > distanceToPinch + threshold) {

              hand.inputState.pinching = false;
              this.dispatchEvent({
                type: "pinchend",
                handedness: inputSource.handedness,
                target: this
              });

            } else if (!hand.inputState.pinching && distance <= distanceToPinch - threshold) {

              hand.inputState.pinching = true;
              this.dispatchEvent({
                type: "pinchstart",
                handedness: inputSource.handedness,
                target: this
              });

            }

          }

        }

      } else {

        if (targetRay !== null) {

          inputPose = frame.getPose(inputSource.targetRaySpace, referenceSpace);

          if (inputPose !== null) {

            targetRay.matrix.fromArray(inputPose.transform.matrix);
            targetRay.matrix.decompose(targetRay.position, targetRay.rotation, targetRay.scale);

          }

        }

        if (grip !== null && inputSource.gripSpace) {

          gripPose = frame.getPose(inputSource.gripSpace, referenceSpace);

          if (gripPose !== null) {

            grip.matrix.fromArray(gripPose.transform.matrix);
            grip.matrix.decompose(grip.position, grip.rotation, grip.scale);

          }

        }

      }

    }

    if (targetRay !== null) {

      targetRay.visible = (inputPose !== null);

    }

    if (grip !== null) {

      grip.visible = (gripPose !== null);

    }

    if (hand !== null) {

      hand.visible = (handPose !== null);

    }

    return this;

  }

});


export {WebXRController};
